#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
记忆管理模块

提供短期记忆和长期记忆的管理功能，包括自动删除和总结机制。
"""

import json
import os
import re
from datetime import datetime
from pathlib import Path
from typing import Any, Dict, List, Optional

from core.utils.log import mylogger


class MemoryUtils:
    """记忆管理工具类"""

    def __init__(
        self, npc_name: str, base_dir: Optional[str] = None, llm_instance=None, model_type: Optional[str] = None
    ):
        self.npc_name = npc_name
        self.model_type = model_type or "default"
        self.llm = llm_instance  # LLM实例需要从外部传入

        # 设置存储路径
        if base_dir is None:
            # 确保使用项目根目录下的data/memory路径
            project_root = Path(__file__).parent.parent.parent
            base_dir = str(project_root / "data" / "memory")

        self.short_term_dir = os.path.join(base_dir, "short_term")
        self.long_term_dir = os.path.join(base_dir, "long_term")

        # 确保目录存在
        os.makedirs(self.short_term_dir, exist_ok=True)
        os.makedirs(self.long_term_dir, exist_ok=True)

        # 记忆限制配置
        self.SHORT_TERM_LIMIT = 10
        self.LONG_TERM_LIMIT = 5

    def _get_memory_file_path(self, memory_type: str) -> str:
        """获取记忆文件路径"""
        if memory_type == "short":
            return os.path.join(
                self.short_term_dir, f"{self.npc_name}_{self.model_type}_short_memories.json"
            )
        else:
            return os.path.join(
                self.long_term_dir, f"{self.npc_name}_{self.model_type}_long_memories.json"
            )

    def _load_memories(self, memory_type: str) -> List[Dict[str, Any]]:
        """加载记忆数据"""
        file_path = self._get_memory_file_path(memory_type)

        if not os.path.exists(file_path):
            return []

        try:
            with open(file_path, "r", encoding="utf-8") as f:
                return json.load(f)
        except Exception as e:
            mylogger.error(f"加载{memory_type}记忆失败: {e}")
            return []

    def _save_memories(self, memories: List[Dict[str, Any]], memory_type: str):
        """保存记忆数据"""
        file_path = self._get_memory_file_path(memory_type)

        try:
            with open(file_path, "w", encoding="utf-8") as f:
                json.dump(memories, f, ensure_ascii=False, indent=2)
            mylogger.debug(f"已保存{len(memories)}条{memory_type}记忆")
        except Exception as e:
            mylogger.error(f"保存{memory_type}记忆失败: {e}")

    async def add_short_term_memory(
        self, content: str, memory_type: str = "Conversation"
    ) -> bool:
        """添加短期记忆

        Args:
            content: 记忆内容
            memory_type: 记忆类型（dialogue, action, emotion等）

        Returns:
            bool: 是否成功添加
        """
        try:
            # 加载现有短期记忆
            short_memories = self._load_memories("short")

            # 创建新的记忆条目
            new_memory = {
                "timestamp": datetime.now().isoformat(),
                "type": memory_type,
                "content": content,
            }

            # 添加新记忆
            short_memories.append(new_memory)

            # 检查是否超过限制
            if len(short_memories) > self.SHORT_TERM_LIMIT:
                # 删除最旧的记忆（第一个）
                removed_memory = short_memories.pop(0)
                mylogger.debug(f"删除最旧的短期记忆: {removed_memory['timestamp']}")

            # 保存更新后的短期记忆
            self._save_memories(short_memories, "short")

            # 检查是否需要总结为长期记忆
            if len(short_memories) == self.SHORT_TERM_LIMIT:
                await self._summarize_to_long_term(short_memories)

            mylogger.info(f"已添加短期记忆，当前共{len(short_memories)}条")
            return True

        except Exception as e:
            mylogger.error(f"添加短期记忆失败: {e}")
            return False

    async def _summarize_to_long_term(self, short_memories: List[Dict[str, Any]]):
        """将短期记忆总结为长期记忆"""
        try:
            # 分类记忆内容
            skill_memories = [m for m in short_memories if m["type"] == "Skill"]
            conversation_memories = [
                m for m in short_memories if m["type"] == "Conversation"
            ]

            # 按时间顺序排序所有记忆
            all_memories_sorted = sorted(short_memories, key=lambda x: x["timestamp"])

            # 准备按时间顺序的完整记忆文本（用于时间分析）
            chronological_text = "\n".join(
                [
                    f"时间: {item['timestamp']} | 类型: {item['type']}\n内容: {item['content']}\n---"
                    for item in all_memories_sorted
                ]
            )

            # 准备分类后的记忆文本
            skill_text = (
                "\n".join(
                    [
                        f"时间: {item['timestamp']}\n内容: {item['content']}\n---"
                        for item in sorted(skill_memories, key=lambda x: x["timestamp"])
                    ]
                )
                if skill_memories
                else "无"
            )

            conversation_text = (
                "\n".join(
                    [
                        f"时间: {item['timestamp']}\n内容: {item['content']}\n---"
                        for item in sorted(
                            conversation_memories, key=lambda x: x["timestamp"]
                        )
                    ]
                )
                if conversation_memories
                else "无"
            )

            # 使用LLM进行记忆总结
            summarize_prompt = f"""
请将以下{self.npc_name}的短期记忆进行智能分析和总结，生成结构化的长期记忆：

【完整时间线记忆】（按时间顺序，重点关注态度变化）：
{chronological_text}

【真实技能事件记录】（这些是确实发生的事情）：
{skill_text}

【对话记录】（需要判断真假）：
{conversation_text}

请按以下格式生成总结（必须严格按照格式，特别是关系和态度部分）：

我是玩家的[关系定位]，我对玩家的态度是[具体态度描述]。[重要事件描述，区分真实发生和虚假承诺]。

**关键分析要求**：
1. **严格区分事实与声称**：
   - 只有"Skill"类型的记录才是确实发生的事实
   - "Conversation"类型中玩家的话只是声称，不是事实
   - 如果玩家声称做了某事，但没有对应的"Skill"记录，则判断为虚假或欺骗
2. **虚假识别逻辑**：
   - 玩家问"你还记得我给你xxx吗？"→如果没有对应Skill记录→判断为玩家在撒谎
   - 玩家说"我昨天给你xxx"→如果没有对应Skill记录→判断为玩家在撒谎
   - NPC的回应不代表事实，可能是配合、误解或其他原因
3. **时间线分析**：仔细查看完整时间线记忆，识别态度和关系的变化过程
4. **关系定位**：基于互动确定我与玩家的关系（如：陌生人、熟人、朋友等）
5. **态度描述**：我对玩家的**最新**态度（如：警惕、友好、贪婪、厌恶等）
6. **性格体现**：通过事件体现我的性格特征
7. **时间优先原则**：如果存在态度或关系的变化，必须以最新的记忆为准

**格式要求**：
- 必须以"我是玩家的[关系]，我对玩家的态度是[态度]"开头
- 关系和态度必须使用单一、明确的词语描述，不要使用复合词
- 关系可选值包括：陌生人、熟人、朋友、敌人、仇人等
- 态度可选值包括：友好、贪婪、警惕、厌恶、喜欢、讨厌、信任、怀疑、感激、愤怒、不屑、鄙视等

总结长度控制在100字以内，语言要符合{self.npc_name}的说话风格。
"""

            messages = [
                {
                    "role": "system",
                    "content": "你是一个专业的记忆分析师，擅长区分真实事件和虚假承诺，能够准确分析人物关系和态度变化。",
                },
                {"role": "user", "content": summarize_prompt},
            ]

            if self.llm is None:
                raise ValueError("LLM实例未提供，无法进行记忆总结")
            summary = await self.llm.chat(messages)

            # 添加到长期记忆
            await self._add_long_term_memory(summary)

            # 保留最近的2条记录，而不是全部清空
            recent_memories = sorted(short_memories, key=lambda x: x["timestamp"])[-2:]
            self._save_memories(recent_memories, "short")

            mylogger.info(
                f"{self.npc_name}的{len(short_memories)}条短期记忆已智能总结为长期记忆，保留最近{len(recent_memories)}条"
            )

        except Exception as e:
            mylogger.error(f"总结短期记忆失败: {e}")

    async def _add_long_term_memory(self, content: str):
        """添加长期记忆"""
        try:
            # 加载现有长期记忆
            long_memories = self._load_memories("long")

            # 尝试解析内容中的结构化信息
            relationship = "未知"
            attitude = "未知"

            # 增强的关系和态度提取逻辑
            # 提取关系信息 - 支持多种表达方式
            relationship_patterns = [
                ("我是玩家的", 5),
                ("跟玩家是", 4),
                ("与玩家是", 4),
                ("和玩家是", 4),
                ("跟玩家就是", 5),
                ("跟玩家就是个", 6),
                ("与玩家就是", 5),
                ("和玩家就是", 5),
                ("我和玩家是", 5),
                ("我与玩家是", 5),
                ("跟玩家是", 5),
                ("我对玩家来说是", 7),
                ("玩家对我来说是", 7),
                ("玩家和我是", 5),
                ("玩家与我是", 5),
            ]

            # 先尝试精确匹配
            relationship_found = False
            for pattern, offset in relationship_patterns:
                if pattern in content:
                    try:
                        start = content.find(pattern) + offset
                        # 寻找多种可能的结束符
                        end_chars = [
                            "，",
                            "。",
                            "；",
                            "、",
                            "！",
                            "?",
                            "？",
                            "）",
                            ")",
                            "」",
                        ]
                        end = len(content)
                        for char in end_chars:
                            char_pos = content.find(char, start)
                            if char_pos > start and char_pos < end:
                                end = char_pos
                        if end > start:
                            relationship = content[start:end].strip()
                            relationship_found = True
                            break
                    except:
                        pass

            # 如果精确匹配失败，尝试更宽松的匹配
            if not relationship_found:
                # 常见关系词列表
                relationship_keywords = [
                    "陌生人",
                    "朋友",
                    "熟人",
                    "敌人",
                    "仇人",
                    "恋人",
                    "伙伴",
                    "同事",
                    "师徒",
                ]
                for keyword in relationship_keywords:
                    if (
                        keyword in content
                        and "不是" + keyword not in content
                        and "不算" + keyword not in content
                    ):
                        relationship = keyword
                        break

            # 提取态度信息 - 支持多种表达方式
            attitude_patterns = [
                ("我对玩家的态度是", 8),
                ("对他的态度是", 6),
                ("对她的态度是", 6),
                ("对玩家的态度是", 7),
                ("对玩家态度", 5),
                ("态度是", 3),
                ("我对玩家", 4),
                ("对玩家", 3),
            ]

            # 先尝试精确匹配
            attitude_found = False
            for pattern, offset in attitude_patterns:
                if pattern in content:
                    try:
                        start = content.find(pattern) + offset
                        # 寻找多种可能的结束符
                        end_chars = [
                            "。",
                            "，",
                            "；",
                            "、",
                            "！",
                            "?",
                            "？",
                            "）",
                            ")",
                            "」",
                        ]
                        end = len(content)
                        for char in end_chars:
                            char_pos = content.find(char, start)
                            if char_pos > start and char_pos < end:
                                end = char_pos
                        if end > start:
                            attitude = content[start:end].strip()
                            attitude_found = True
                            break
                    except:
                        pass

            # 如果精确匹配失败，尝试更宽松的匹配
            if not attitude_found:
                # 扩展态度关键词列表
                attitude_keywords = [
                    "友好",
                    "贪婪",
                    "警惕",
                    "厌恶",
                    "喜欢",
                    "讨厌",
                    "信任",
                    "怀疑",
                    "感激",
                    "愤怒",
                    "不屑",
                    "鄙视",
                    "尊敬",
                    "崇拜",
                    "嫉妒",
                    "羡慕",
                    "同情",
                    "关心",
                    "冷漠",
                    "热情",
                    "敌意",
                    "亲近",
                    "疏远",
                    "好奇",
                    "反感",
                    "憎恨",
                    "恐惧",
                    "依赖",
                    "不信任",
                    "欣赏",
                ]

                for keyword in attitude_keywords:
                    if keyword in content:
                        # 检查是否有否定词
                        negation_words = [
                            "不",
                            "没",
                            "无",
                            "非",
                            "莫",
                            "勿",
                            "毫无",
                            "绝不",
                        ]
                        negated = False
                        for neg in negation_words:
                            neg_pos = content.find(neg + keyword)
                            if neg_pos >= 0 and neg_pos < content.find(keyword):
                                negated = True
                                break

                        if not negated:
                            attitude = keyword
                            break

            # 如果提取到的态度包含多个情绪词，尝试提取最主要的一个
            if attitude != "未知" and len(attitude) > 4:
                # 如果态度描述中包含"最新"、"现在"等时间词汇，优先提取
                if "最新" in attitude or "现在" in attitude or "目前" in attitude:
                    # 进一步提取具体态度词汇
                    attitude_keywords = [
                        "友好",
                        "贪婪",
                        "警惕",
                        "厌恶",
                        "喜欢",
                        "讨厌",
                        "信任",
                        "怀疑",
                        "感激",
                        "愤怒",
                        "不屑",
                        "鄙视",
                        "尊敬",
                        "崇拜",
                        "嫉妒",
                        "羡慕",
                        "同情",
                        "关心",
                        "冷漠",
                        "热情",
                        "敌意",
                        "亲近",
                        "疏远",
                        "好奇",
                        "反感",
                        "憎恨",
                        "恐惧",
                        "依赖",
                        "不信任",
                        "欣赏",
                    ]
                    for keyword in attitude_keywords:
                        if keyword in attitude:
                            attitude = keyword
                            break
                # 如果态度中包含"和"、"与"等连接词，可能有多个情绪，取第一个
                elif "和" in attitude or "与" in attitude or "以及" in attitude:
                    parts = re.split(r"[和与以及]", attitude)
                    if parts:
                        attitude = parts[0].strip()

            # 创建增强的长期记忆条目
            new_memory = {
                "timestamp": datetime.now().isoformat(),
                "content": content,
                "source": "short_term_summary",  # 标记来源
                "metadata": {
                    "relationship": relationship,
                    "attitude": attitude,
                    "npc_name": self.npc_name,
                },
            }

            # 添加新记忆
            long_memories.append(new_memory)

            # 检查是否超过限制
            if len(long_memories) > self.LONG_TERM_LIMIT:
                # 删除最旧的记忆（第一个）
                removed_memory = long_memories.pop(0)
                mylogger.debug(f"删除最旧的长期记忆: {removed_memory['timestamp']}")

            # 保存更新后的长期记忆
            self._save_memories(long_memories, "long")

            mylogger.info(f"已添加结构化长期记忆，当前共{len(long_memories)}条")
            mylogger.debug(f"关系: {relationship}, 态度: {attitude}")

        except Exception as e:
            mylogger.error(f"添加长期记忆失败: {e}")

    def get_short_term_memories(
        self, limit: Optional[int] = None
    ) -> List[Dict[str, Any]]:
        """获取短期记忆

        Args:
            limit: 限制返回数量，None表示返回所有

        Returns:
            List[Dict]: 短期记忆列表
        """
        memories = self._load_memories("short")
        if limit is not None:
            return memories[-limit:]  # 返回最新的几条
        return memories

    def get_long_term_memories(
        self, limit: Optional[int] = None
    ) -> List[Dict[str, Any]]:
        """获取长期记忆

        Args:
            limit: 限制返回数量，None表示返回所有

        Returns:
            List[Dict]: 长期记忆列表
        """
        memories = self._load_memories("long")
        if limit is not None:
            return memories[-limit:]  # 返回最新的几条
        return memories

    def get_memory_context(self, short_limit: int = 3, long_limit: int = 2) -> str:
        """获取记忆上下文，用于对话生成

        Args:
            short_limit: 短期记忆数量限制
            long_limit: 长期记忆数量限制

        Returns:
            str: 格式化的记忆上下文
        """
        context_parts = []

        # 获取长期记忆
        long_memories = self.get_long_term_memories(long_limit)
        if long_memories:
            context_parts.append("=== 长期记忆 ===")
            for memory in long_memories:
                context_parts.append(f"时间: {memory['timestamp']}")

                # 显示结构化信息（如果存在）
                if "metadata" in memory:
                    metadata = memory["metadata"]
                    if metadata.get("relationship", "未知") != "未知":
                        context_parts.append(f"关系: {metadata['relationship']}")
                    if metadata.get("attitude", "未知") != "未知":
                        context_parts.append(f"态度: {metadata['attitude']}")

                context_parts.append(f"内容: {memory['content']}")
                context_parts.append("---")

        # 获取短期记忆
        short_memories = self.get_short_term_memories(short_limit)
        if short_memories:
            context_parts.append("\n=== 短期记忆 ===")
            for memory in short_memories:
                context_parts.append(f"时间: {memory['timestamp']}")
                context_parts.append(f"类型: {memory['type']}")
                context_parts.append(f"内容: {memory['content']}")
                context_parts.append("---")

        return "\n".join(context_parts) if context_parts else ""

    def get_memory_stats(self) -> Dict[str, int]:
        """获取记忆统计信息

        Returns:
            Dict: 包含短期和长期记忆数量的统计
        """
        short_count = len(self.get_short_term_memories())
        long_count = len(self.get_long_term_memories())

        return {
            "short_term_count": short_count,
            "long_term_count": long_count,
            "short_term_limit": self.SHORT_TERM_LIMIT,
            "long_term_limit": self.LONG_TERM_LIMIT,
        }

    async def clear_all_memories(self):
        """清空所有记忆（谨慎使用）"""
        try:
            self._save_memories([], "short")
            self._save_memories([], "long")
            mylogger.warning(f"已清空{self.npc_name}的所有记忆")
        except Exception as e:
            mylogger.error(f"清空记忆失败: {e}")


class MemoryManager:
    """记忆管理器，管理所有NPC的记忆工具实例"""

    def __init__(self, llm_instance=None):
        self.memory_utils: Dict[str, MemoryUtils] = {}
        self.llm_instance = llm_instance

    def get_memory_utils(self, npc_name: str, llm_instance=None, model_type: Optional[str] = None) -> MemoryUtils:
        """获取或创建NPC的记忆工具实例"""
        # 使用npc_name和model_type组合作为key，确保不同模型的记忆工具独立
        memory_key = f"{npc_name}_{model_type or 'default'}"
        if memory_key not in self.memory_utils:
            # 优先使用传入的llm_instance，否则使用初始化时的实例
            llm_to_use = llm_instance or self.llm_instance
            self.memory_utils[memory_key] = MemoryUtils(npc_name, llm_instance=llm_to_use, model_type=model_type)
            mylogger.info(f"为 {npc_name} ({model_type or 'default'}) 创建了记忆管理工具")

        return self.memory_utils[memory_key]

    async def add_memory(
        self, npc_name: str, content: str, memory_type: str = "Conversation", model_type: Optional[str] = None
    ) -> bool:
        """为指定NPC添加记忆"""
        memory_utils = self.get_memory_utils(npc_name, model_type=model_type)
        return await memory_utils.add_short_term_memory(content, memory_type)

    def get_context(self, npc_name: str, model_type: Optional[str] = None) -> str:
        """获取指定NPC的记忆上下文"""
        memory_utils = self.get_memory_utils(npc_name, model_type=model_type)
        return memory_utils.get_memory_context()

    def get_stats(self, npc_name: str, model_type: Optional[str] = None) -> Dict[str, int]:
        """获取指定NPC的记忆统计"""
        memory_utils = self.get_memory_utils(npc_name, model_type=model_type)
        return memory_utils.get_memory_stats()


memory_manager = MemoryManager()
